"""
Base API class following SOLID principles.
"""

from typing import Any, Dict, Optional, Type, List
from abc import ABC, abstractmethod
from fastapi import Request, Depends
from sqlalchemy.orm import Session

from ..database import get_db
from ..auth import get_current_user, User
from ..logging import get_logger
from .responses import APIResponse, SuccessResponse, ErrorResponse
from .exceptions import APIException, ValidationError, NotFoundError


class BaseAPI(ABC):
    """Base API class implementing common functionality."""
    
    def __init__(self):
        self.logger = get_logger(self.__class__.__name__)
    
    def get_request_id(self, request: Request) -> Optional[str]:
        """Get request ID from request headers."""
        return request.headers.get("X-Request-ID")
    
    def log_request(self, request: Request, **kwargs):
        """Log incoming request."""
        self.logger.info(
            "API request",
            method=request.method,
            url=str(request.url),
            client_ip=request.client.host if request.client else None,
            user_agent=request.headers.get("User-Agent"),
            **kwargs
        )
    
    def log_response(self, request: Request, response_data: Any, **kwargs):
        """Log API response."""
        self.logger.info(
            "API response",
            method=request.method,
            url=str(request.url),
            response_type=type(response_data).__name__,
            **kwargs
        )
    
    def handle_exception(self, request: Request, exc: Exception) -> ErrorResponse:
        """Handle API exceptions."""
        request_id = self.get_request_id(request)
        
        if isinstance(exc, APIException):
            self.logger.warning(
                "API exception",
                error_code=exc.error_code,
                detail=exc.detail,
                status_code=exc.status_code,
                request_id=request_id
            )
            return ErrorResponse.create(
                message=exc.detail.get("message", str(exc.detail)) if isinstance(exc.detail, dict) else str(exc.detail),
                error_code=exc.error_code,
                error_details=exc.extra_data,
                request_id=request_id
            )
        else:
            self.logger.error(
                "Unexpected error",
                error=str(exc),
                error_type=type(exc).__name__,
                request_id=request_id,
                exc_info=True
            )
            return ErrorResponse.create(
                message="Internal server error",
                error_code="INTERNAL_ERROR",
                request_id=request_id
            )
    
    def create_success_response(
        self,
        data: Any,
        message: str = "Success",
        request_id: Optional[str] = None
    ) -> SuccessResponse:
        """Create success response."""
        return SuccessResponse.create(
            data=data,
            message=message,
            request_id=request_id
        )
    
    def validate_pagination_params(
        self,
        page: int = 1,
        size: int = 20,
        max_size: int = 100
    ) -> Dict[str, int]:
        """Validate pagination parameters."""
        if page < 1:
            raise ValidationError("Page must be greater than 0")
        
        if size < 1:
            raise ValidationError("Size must be greater than 0")
        
        if size > max_size:
            raise ValidationError(f"Size cannot exceed {max_size}")
        
        return {
            "page": page,
            "size": size,
            "offset": (page - 1) * size
        }


class CRUDBaseAPI(BaseAPI):
    """Base CRUD API class."""
    
    def __init__(self, model_class: Type, service_class: Type):
        super().__init__()
        self.model_class = model_class
        self.service_class = service_class
    
    @abstractmethod
    def get_service(self, db: Session) -> Any:
        """Get service instance."""
        pass
    
    def get_item_or_404(self, db: Session, item_id: Any) -> Any:
        """Get item by ID or raise 404."""
        service = self.get_service(db)
        item = service.get_by_id(item_id)
        if not item:
            raise NotFoundError(
                detail=f"{self.model_class.__name__} not found",
                resource_type=self.model_class.__name__,
                resource_id=str(item_id)
            )
        return item
    
    def check_item_exists(self, db: Session, item_id: Any) -> bool:
        """Check if item exists."""
        service = self.get_service(db)
        return service.exists(item_id)


class AuthenticatedAPI(BaseAPI):
    """Base API class for authenticated endpoints."""
    
    def get_current_user_dependency(self):
        """Get current user dependency."""
        return Depends(get_current_user)
    
    def check_user_permission(
        self,
        user: User,
        resource: Any,
        action: str
    ) -> bool:
        """Check if user has permission for action on resource."""
        # Implement your permission logic here
        # This is a placeholder implementation
        return True
    
    def require_permission(
        self,
        user: User,
        resource: Any,
        action: str
    ):
        """Require user permission or raise exception."""
        if not self.check_user_permission(user, resource, action):
            from .exceptions import ForbiddenError
            raise ForbiddenError(
                detail=f"Permission denied for action '{action}'"
            )


class AdminAPI(AuthenticatedAPI):
    """Base API class for admin endpoints."""
    
    def check_admin_permission(self, user: User) -> bool:
        """Check if user has admin permission."""
        # Implement your admin check logic here
        return getattr(user, 'is_admin', False)
    
    def require_admin(self, user: User):
        """Require admin permission or raise exception."""
        if not self.check_admin_permission(user):
            from .exceptions import ForbiddenError
            raise ForbiddenError(
                detail="Admin permission required"
            )


class PublicAPI(BaseAPI):
    """Base API class for public endpoints."""
    
    def __init__(self):
        super().__init__()
        # Public APIs might have different rate limiting or caching
        self.rate_limit_enabled = True
        self.cache_enabled = True


class HealthCheckAPI(PublicAPI):
    """Health check API."""
    
    def __init__(self):
        super().__init__()
        self.start_time = None
    
    def get_health_status(self) -> Dict[str, Any]:
        """Get application health status."""
        import time
        
        status = {
            "status": "healthy",
            "timestamp": time.time(),
            "uptime": time.time() - (self.start_time or time.time()),
            "version": "1.0.0"  # You can get this from your app config
        }
        
        # Add dependency checks here
        dependencies = self.check_dependencies()
        if dependencies:
            status["dependencies"] = dependencies
        
        return status
    
    def check_dependencies(self) -> Dict[str, str]:
        """Check external dependencies."""
        dependencies = {}
        
        # Check database
        try:
            # Add your database check here
            dependencies["database"] = "healthy"
        except Exception as e:
            dependencies["database"] = f"unhealthy: {str(e)}"
        
        # Check Redis
        try:
            # Add your Redis check here
            dependencies["redis"] = "healthy"
        except Exception as e:
            dependencies["redis"] = f"unhealthy: {str(e)}"
        
        return dependencies